import unittest
import pygame
from pgzero.rect import ZRect as Rect


class RectTypeTest(unittest.TestCase):
    def testConstructionXYWidthHeight(self):
        r = Rect(1, 2, 3, 4)
        self.assertEqual(1, r.left)
        self.assertEqual(2, r.top)
        self.assertEqual(3, r.width)
        self.assertEqual(4, r.height)

    def testConstructionTopLeftSize(self):
        r = Rect((1, 2), (3, 4))
        self.assertEqual(1, r.left)
        self.assertEqual(2, r.top)
        self.assertEqual(3, r.width)
        self.assertEqual(4, r.height)

    def testCalculatedAttributes(self):
        r = Rect(1, 2, 3, 4)

        self.assertEqual(r.left+r.width, r.right)
        self.assertEqual(r.top+r.height, r.bottom)
        self.assertEqual((r.width, r.height), r.size)
        self.assertEqual((r.left, r.top), r.topleft)
        self.assertEqual((r.right, r.top), r.topright)
        self.assertEqual((r.left, r.bottom), r.bottomleft)
        self.assertEqual((r.right, r.bottom), r.bottomright)

        midx = r.left + r.width / 2
        midy = r.top + r.height / 2

        self.assertEqual(midx, r.centerx)
        self.assertEqual(midy, r.centery)
        self.assertEqual((r.centerx, r.centery), r.center)
        self.assertEqual((r.centerx, r.top), r.midtop)
        self.assertEqual((r.centerx, r.bottom), r.midbottom)
        self.assertEqual((r.left, r.centery), r.midleft)
        self.assertEqual((r.right, r.centery), r.midright)

    def test_normalize(self):
        r = Rect(1, 2, -3, -6)
        r2 = Rect(r)
        r2.normalize()
        self.assertTrue(r2.width >= 0)
        self.assertTrue(r2.height >= 0)
        self.assertEqual((abs(r.width), abs(r.height)), r2.size)
        self.assertEqual((-2, -4), r2.topleft)

    def test_left(self):
        """Changing the left attribute moves the rect and does not change
           the rect's width
        """
        r = Rect(1, 2, 3, 4)
        new_left = 10

        r.left = new_left
        self.assertEqual(new_left, r.left)
        self.assertEqual(Rect(new_left, 2, 3, 4), r)

    def test_right(self):
        """Changing the right attribute moves the rect and does not change
           the rect's width
        """
        r = Rect(1, 2, 3, 4)
        new_right = r.right + 20
        expected_left = r.left + 20
        old_width = r.width

        r.right = new_right
        self.assertEqual(new_right, r.right)
        self.assertEqual(expected_left, r.left)
        self.assertEqual(old_width, r.width)

    def test_top(self):
        """Changing the top attribute moves the rect and does not change
           the rect's width
        """
        r = Rect(1, 2, 3, 4)
        new_top = 10

        r.top = new_top
        self.assertEqual(Rect(1, new_top, 3, 4), r)
        self.assertEqual(new_top, r.top)

    def test_bottom(self):
        """Changing the bottom attribute moves the rect and does not change
           the rect's height
        """
        r = Rect(1, 2, 3, 4)
        new_bottom = r.bottom + 20
        expected_top = r.top + 20
        old_height = r.height

        r.bottom = new_bottom
        self.assertEqual(new_bottom, r.bottom)
        self.assertEqual(expected_top, r.top)
        self.assertEqual(old_height, r.height)

    def test_centerx(self):
        """Changing the centerx attribute moves the rect and does not change
           the rect's width
        """
        r = Rect(1, 2, 3, 4)
        new_centerx = r.centerx + 20
        expected_left = r.left + 20
        old_width = r.width

        r.centerx = new_centerx
        self.assertEqual(new_centerx, r.centerx)
        self.assertEqual(expected_left, r.left)
        self.assertEqual(old_width, r.width)

    def test_centery(self):
        """Changing the centerx attribute moves the rect and does not change
           the rect's width
        """
        r = Rect(1, 2, 3, 4)
        new_centery = r.centery + 20
        expected_top = r.top + 20
        old_height = r.height

        r.centery = new_centery
        self.assertEqual(new_centery, r.centery)
        self.assertEqual(expected_top, r.top)
        self.assertEqual(old_height, r.height)

    def test_topleft(self):
        """Changing the topleft attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.topleft = new_topleft
        self.assertEqual(new_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_bottomleft(self):
        """Changing the bottomleft attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_bottomleft = (r.left+20, r.bottom+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.bottomleft = new_bottomleft
        self.assertEqual(new_bottomleft, r.bottomleft)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_topright(self):
        """Changing the bottomleft attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_topright = (r.right+20, r.top+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.topright = new_topright
        self.assertEqual(new_topright, r.topright)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_bottomright(self):
        """Changing the bottomright attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_bottomright = (r.right+20, r.bottom+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.bottomright = new_bottomright
        self.assertEqual(new_bottomright, r.bottomright)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_center(self):
        """Changing the center attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_center = (r.centerx+20, r.centery+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.center = new_center
        self.assertEqual(new_center, r.center)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_midleft(self):
        """Changing the midleft attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_midleft = (r.left+20, r.centery+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.midleft = new_midleft
        self.assertEqual(new_midleft, r.midleft)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_midright(self):
        """Changing the midright attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_midright = (r.right+20, r.centery+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.midright = new_midright
        self.assertEqual(new_midright, r.midright)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_midtop(self):
        """Changing the midtop attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_midtop = (r.centerx+20, r.top+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.midtop = new_midtop
        self.assertEqual(new_midtop, r.midtop)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_midbottom(self):
        """Changing the midbottom attribute moves the rect and does not change
           the rect's size
        """
        r = Rect(1, 2, 3, 4)
        new_midbottom = (r.centerx+20, r.bottom+30)
        expected_topleft = (r.left+20, r.top+30)
        old_size = r.size

        r.midbottom = new_midbottom
        self.assertEqual(new_midbottom, r.midbottom)
        self.assertEqual(expected_topleft, r.topleft)
        self.assertEqual(old_size, r.size)

    def test_width(self):
        "Changing the width resizes the rect from the top-left corner"
        r = Rect(1, 2, 3, 4)
        new_width = 10
        old_topleft = r.topleft
        old_height = r.height

        r.width = new_width
        self.assertEqual(new_width, r.width)
        self.assertEqual(old_height, r.height)
        self.assertEqual(old_topleft, r.topleft)

    def test_height(self):
        "Changing the height resizes the rect from the top-left corner"
        r = Rect(1, 2, 3, 4)
        new_height = 10
        old_topleft = r.topleft
        old_width = r.width

        r.height = new_height
        self.assertEqual(new_height, r.height)
        self.assertEqual(old_width, r.width)
        self.assertEqual(old_topleft, r.topleft)

    def test_size(self):
        "Changing the size resizes the rect from the top-left corner"
        r = Rect(1, 2, 3, 4)
        new_size = (10, 20)
        old_topleft = r.topleft

        r.size = new_size
        self.assertEqual(new_size, r.size)
        self.assertEqual(old_topleft, r.topleft)

    def test_contains(self):
        r = Rect(1, 2, 3, 4)

        self.assertTrue(r.contains(Rect(2, 3, 1, 1)),
                        "r does not contain Rect(2,3,1,1)")
        self.assertTrue(r.contains(Rect(r)),
                        "r does not contain the same rect as itself")
        self.assertTrue(r.contains(Rect(2, 3, 0, 0)),
                        "r does not contain an empty rect within its bounds")
        self.assertFalse(r.contains(Rect(0, 0, 1, 2)),
                         "r contains Rect(0,0,1,2)")
        self.assertFalse(r.contains(Rect(4, 6, 1, 1)),
                         "r contains Rect(4,6,1,1)")
        self.assertFalse(r.contains(Rect(4, 6, 0, 0)),
                         "r contains Rect(4,6,0,0)")

    def test_collidepoint(self):
        r = Rect(1, 2, 3, 4)

        self.assertTrue(r.collidepoint(r.left, r.top),
                        "r does not collide with point (left,top)")
        self.assertFalse(r.collidepoint(r.left-1, r.top),
                         "r collides with point (left-1,top)")
        self.assertFalse(r.collidepoint(r.left, r.top-1),
                         "r collides with point (left,top-1)")
        self.assertFalse(r.collidepoint(r.left-1, r.top-1),
                         "r collides with point (left-1,top-1)")

        self.assertTrue(r.collidepoint(r.right-1, r.bottom-1),
                        "r does not collide with point (right-1,bottom-1)")
        self.assertFalse(r.collidepoint(r.right, r.bottom),
                         "r collides with point (right,bottom)")
        self.assertFalse(r.collidepoint(r.right-1, r.bottom),
                         "r collides with point (right-1,bottom)")
        self.assertFalse(r.collidepoint(r.right, r.bottom-1),
                         "r collides with point (right,bottom-1)")

    def test_inflate__larger(self):
        "The inflate method inflates around the center of the rectangle"
        r = Rect(2, 4, 6, 8)
        r2 = r.inflate(4, 6)

        self.assertEqual(r.center, r2.center)
        self.assertEqual(r.left-2, r2.left)
        self.assertEqual(r.top-3, r2.top)
        self.assertEqual(r.right+2, r2.right)
        self.assertEqual(r.bottom+3, r2.bottom)
        self.assertEqual(r.width+4, r2.width)
        self.assertEqual(r.height+6, r2.height)

    def test_inflate__smaller(self):
        "The inflate method inflates around the center of the rectangle"
        r = Rect(2, 4, 6, 8)
        r2 = r.inflate(-4, -6)

        self.assertEqual(r.center, r2.center)
        self.assertEqual(r.left+2, r2.left)
        self.assertEqual(r.top+3, r2.top)
        self.assertEqual(r.right-2, r2.right)
        self.assertEqual(r.bottom-3, r2.bottom)
        self.assertEqual(r.width-4, r2.width)
        self.assertEqual(r.height-6, r2.height)

    def test_inflate_ip__larger(self):
        "The inflate_ip method inflates around the center of the rectangle"
        r = Rect(2, 4, 6, 8)
        r2 = Rect(r)
        r2.inflate_ip(-4, -6)

        self.assertEqual(r.center, r2.center)
        self.assertEqual(r.left+2, r2.left)
        self.assertEqual(r.top+3, r2.top)
        self.assertEqual(r.right-2, r2.right)
        self.assertEqual(r.bottom-3, r2.bottom)
        self.assertEqual(r.width-4, r2.width)
        self.assertEqual(r.height-6, r2.height)

    def test_inflate_ip__smaller(self):
        "The inflate method inflates around the center of the rectangle"
        r = Rect(2, 4, 6, 8)
        r2 = Rect(r)
        r2.inflate_ip(-4, -6)

        self.assertEqual(r.center, r2.center)
        self.assertEqual(r.left+2, r2.left)
        self.assertEqual(r.top+3, r2.top)
        self.assertEqual(r.right-2, r2.right)
        self.assertEqual(r.bottom-3, r2.bottom)
        self.assertEqual(r.width-4, r2.width)
        self.assertEqual(r.height-6, r2.height)

    def test_clamp(self):
        r = Rect(10, 10, 10, 10)
        c = Rect(19, 12, 5, 5).clamp(r)
        self.assertEqual(c.right, r.right)
        self.assertEqual(c.top, 12)
        c = Rect(1, 2, 3, 4).clamp(r)
        self.assertEqual(c.topleft, r.topleft)
        c = Rect(5, 500, 22, 33).clamp(r)
        self.assertEqual(c.center, r.center)

    def test_clamp_ip(self):
        r = Rect(10, 10, 10, 10)
        c = Rect(19, 12, 5, 5)
        c.clamp_ip(r)
        self.assertEqual(c.right, r.right)
        self.assertEqual(c.top, 12)
        c = Rect(1, 2, 3, 4)
        c.clamp_ip(r)
        self.assertEqual(c.topleft, r.topleft)
        c = Rect(5, 500, 22, 33)
        c.clamp_ip(r)
        self.assertEqual(c.center, r.center)

    def test_clip(self):
        r1 = Rect(1, 2, 3, 4)
        self.assertEqual(Rect(1, 2, 2, 2), r1.clip(Rect(0, 0, 3, 4)))
        self.assertEqual(Rect(2, 2, 2, 4), r1.clip(Rect(2, 2, 10, 20)))
        self.assertEqual(Rect(2, 3, 1, 2), r1.clip(Rect(2, 3, 1, 2)))
        self.assertEqual((0, 0), r1.clip(20, 30, 5, 6).size)
        self.assertEqual(r1, r1.clip(Rect(r1)),
                         "r1 does not clip an identical rect to itself")

    def test_move(self):
        r = Rect(1, 2, 3, 4)
        move_x = 10
        move_y = 20
        r2 = r.move(move_x, move_y)
        expected_r2 = Rect(r.left+move_x, r.top+move_y, r.width, r.height)
        self.assertEqual(expected_r2, r2)

    def test_move_ip(self):
        r = Rect(1, 2, 3, 4)
        r2 = Rect(r)
        move_x = 10
        move_y = 20
        r2.move_ip(move_x, move_y)
        expected_r2 = Rect(r.left+move_x, r.top+move_y, r.width, r.height)
        self.assertEqual(expected_r2, r2)

    def test_union(self):
        r1 = Rect(1, 1, 1, 2)
        r2 = Rect(-2, -2, 1, 2)
        self.assertEqual(Rect(-2, -2, 4, 5), r1.union(r2))

    def test_union__with_identical_Rect(self):
        r1 = Rect(1, 2, 3, 4)
        self.assertEqual(r1, r1.union(Rect(r1)))

    def test_union_ip(self):
        r1 = Rect(1, 1, 1, 2)
        r2 = Rect(-2, -2, 1, 2)
        r1.union_ip(r2)
        self.assertEqual(Rect(-2, -2, 4, 5), r1)

    def test_unionall(self):
        r1 = Rect(0, 0, 1, 1)
        r2 = Rect(-2, -2, 1, 1)
        r3 = Rect(2, 2, 1, 1)

        r4 = r1.unionall([r2, r3])
        self.assertEqual(Rect(-2, -2, 5, 5), r4)

    def test_unionall_ip(self):
        r1 = Rect(0, 0, 1, 1)
        r2 = Rect(-2, -2, 1, 1)
        r3 = Rect(2, 2, 1, 1)

        r1.unionall_ip([r2, r3])
        self.assertEqual(Rect(-2, -2, 5, 5), r1)

    def test_colliderect(self):
        r1 = Rect(1, 2, 3, 4)
        self.assertTrue(r1.colliderect(Rect(0, 0, 2, 3)),
                        "r1 does not collide with Rect(0,0,2,3)")
        self.assertFalse(r1.colliderect(Rect(0, 0, 1, 2)),
                         "r1 collides with Rect(0,0,1,2)")
        self.assertFalse(r1.colliderect(Rect(r1.right, r1.bottom, 2, 2)),
                         "r1 collides with Rect(r1.right,r1.bottom,2,2)")
        self.assertTrue(r1.colliderect(Rect(r1.left+1, r1.top+1,
                                            r1.width-2, r1.height-2)),
                        "r1 does not collide with Rect(r1.left+1,r1.top+1," +
                        "r1.width-2,r1.height-2)")
        self.assertTrue(r1.colliderect(Rect(r1.left-1, r1.top-1,
                                            r1.width+2, r1.height+2)),
                        "r1 does not collide with Rect(r1.left-1,r1.top-1," +
                        "r1.width+2,r1.height+2)")
        self.assertTrue(r1.colliderect(Rect(r1)),
                        "r1 does not collide with an identical rect")
        self.assertFalse(r1.colliderect(Rect(r1.right, r1.bottom, 0, 0)),
                         "r1 collides with Rect(r1.right,r1.bottom,0,0)")
        self.assertFalse(r1.colliderect(Rect(r1.right, r1.bottom, 1, 1)),
                         "r1 collides with Rect(r1.right,r1.bottom,1,1)")

    def testEquals(self):
        """ check to see how the rect uses __eq__
        """
        r1 = Rect(1, 2, 3, 4)
        r2 = Rect(10, 20, 30, 40)
        r3 = (10, 20, 30, 40)
        r4 = Rect(10, 20, 30, 40)

        class foo (Rect):
            def __eq__(self, other):
                return id(self) == id(other)

            def __ne__(self, other):
                return id(self) != id(other)

        class foo2 (Rect):
            pass

        r5 = foo(10, 20, 30, 40)
        r6 = foo2(10, 20, 30, 40)

        self.assertNotEqual(r5, r2)

        # because we define equality differently for this subclass.
        self.assertEqual(r6, r2)

        rect_list = [r1, r2, r3, r4, r6]

        # see if we can remove 4 of these.
        rect_list.remove(r2)
        rect_list.remove(r2)
        rect_list.remove(r2)
        rect_list.remove(r2)
        self.assertRaises(ValueError, rect_list.remove, r2)

    def test_collidedict(self):

        # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidedict:

        #   Rect.collidedict(dict): return (key, value)
        #   test if one rectangle in a dictionary intersects
        #
        #   Returns the key and value of the first dictionary value that
        #   collides with the Rect. If no collisions are found, None is
        #   returned.
        #
        #   Rect objects are not hashable and cannot be used as keys in a
        #   dictionary, only as values.

        r = Rect(1, 1, 10, 10)
        r1 = Rect(1, 1, 10, 10)
        r2 = Rect(50, 50, 10, 10)
        r3 = Rect(70, 70, 10, 10)
        r4 = Rect(61, 61, 10, 10)

        d = {1: r1, 2: r2, 3: r3}

        rects_values = 1
        val = r.collidedict(d, rects_values)
        self.assertTrue(val)
        self.assertEqual(len(val), 2)
        self.assertEqual(val[0], 1)
        self.assertEqual(val[1], r1)

        none_d = {2: r2, 3: r3}
        none_val = r.collidedict(none_d, rects_values)
        self.assertFalse(none_val)

        barely_d = {1: r1, 2: r2, 3: r3}
        k3, v3 = r4.collidedict(barely_d, rects_values)
        self.assertEqual(k3, 3)
        self.assertEqual(v3, r3)

    def test_collidedictall(self):

        # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidedictall:

        #   Rect.collidedictall(dict): return [(key, value), ...]
        #   test if all rectangles in a dictionary intersect
        #
        #   Returns a list of all the key and value pairs that intersect with
        #   the Rect. If no collisions are found an empty dictionary is
        #   returned.
        #
        #   Rect objects are not hashable and cannot be used as keys in a
        #   dictionary, only as values.

        r = Rect(1, 1, 10, 10)

        r2 = Rect(1, 1, 10, 10)
        r3 = Rect(5, 5, 10, 10)
        r4 = Rect(10, 10, 10, 10)
        r5 = Rect(50, 50, 10, 10)

        rects_values = 1
        d = {2: r2}
        collisions = r.collidedictall(d, rects_values)
        self.assertEqual(collisions, [(2, r2)])

        d2 = {2: r2, 3: r3, 4: r4, 5: r5}
        l2 = r.collidedictall(d2, rects_values)
        self.assertEqual(l2, [(2, r2), (3, r3), (4, r4)])

    def test_collidelist(self):

        # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelist:

        #   Rect.collidelist(list): return index
        #   test if one rectangle in a list intersects
        #
        #   Test whether the rectangle collides with any in a sequence of
        #   rectangles. The index of the first collision found is returned. If
        #   no collisions are found an index of -1 is returned.

        r = Rect(1, 1, 10, 10)
        other = [Rect(50, 50, 1, 1), Rect(5, 5, 10, 10), Rect(15, 15, 1, 1)]

        self.assertEqual(r.collidelist(other), 1)

        f = [Rect(50, 50, 1, 1), (100, 100, 4, 4)]
        self.assertEqual(r.collidelist(f), -1)

    def test_collidelistall(self):

        # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelistall:

        #   Rect.collidelistall(list): return indices
        #   test if all rectangles in a list intersect
        #
        #   Returns a list of all the indices that contain rectangles that
        #   collide with the Rect. If no intersecting rectangles are found, an
        #   empty list is returned.

        r = Rect(1, 1, 10, 10)

        other = [
            Rect(1, 1, 10, 10),
            Rect(5, 5, 10, 10),
            Rect(15, 15, 1, 1),
            Rect(2, 2, 1, 1),
        ]
        self.assertEqual(r.collidelistall(other), [0, 1, 3])

        f = [Rect(50, 50, 1, 1), Rect(20, 20, 5, 5)]
        self.assertFalse(r.collidelistall(f))

    def test_fit(self):

        # __doc__ (as of 2008-08-02) for pygame.rect.Rect.fit:

        #   Rect.fit(Rect): return Rect
        #   resize and move a rectangle with aspect ratio
        #
        #   Returns a new rectangle that is moved and resized to fit another.
        #   The aspect ratio of the original Rect is preserved, so the new
        #   rectangle may be smaller than the target in either width or height.

        r = Rect(10, 10, 30, 30)

        r2 = Rect(30, 30, 15, 10)

        f = r.fit(r2)
        self.assertTrue(r2.contains(f))

        f2 = r2.fit(r)
        self.assertTrue(r.contains(f2))

    def test_copy(self):
        r = Rect(1, 2, 10, 20)
        c = r.copy()
        self.assertEqual(c, r)


class PGZeroRectText(unittest.TestCase):

    def test_constructor_from_tuple(self):
        "Build a Rect from a 4-item tuple"
        r = Rect((1, 2, 3, 4))
        self.assertEqual(r.x, 1)
        self.assertEqual(r.y, 2)
        self.assertEqual(r.w, 3)
        self.assertEqual(r.h, 4)

    def test_constructor_from_PGZeroRect(self):
        "Build a rect from another pgzero Rect"
        r = Rect(1, 2, 3, 4)
        r1 = Rect(r)
        self.assertEqual(r, r1)
        self.assertIsNot(r, r1)

    def test_constructor_from_PygameRect(self):
        "Build a rect from a pygame Rect"
        r = pygame.Rect(1, 2, 3, 4)
        r1 = Rect(r)
        self.assertEqual(r, r1)
        self.assertIsNot(r, r1)

    def test_constructor_from_rect_tuple(self):
        "Build a rect from an object with a rect attribute which is a tuple"
        class Obj:
            pass
        obj = Obj()
        obj.rect = 1, 2, 3, 4
        r = Rect(obj)
        self.assertEqual(r, Rect(1, 2, 3, 4))

    def test_constructor_from_rect_object(self):
        "Build a rect from an object with a rect attribute which is an object"
        class Obj:
            pass
        obj = Obj()
        obj.rect = Rect(1, 2, 3, 4)
        r = Rect(obj)
        self.assertEqual(r, Rect(1, 2, 3, 4))

    def test_constructor_from_rect_indirect_tuple(self):
        """Build a rect from an object with a rect attribute which
        is an object which has a rect attribute which is a tuple
        """
        class Obj:
            pass
        obj = Obj()
        obj1 = Obj()
        obj1.rect = Rect(1, 2, 3, 4)
        obj.rect = obj1
        r = Rect(obj)
        self.assertEqual(r, Rect(1, 2, 3, 4))

    def test_constructor_from_rect_callable(self):
        """Build a rect from an object with a rect attribute which
        is called and returns a tuple
        """
        class Obj:
            def rect(self):
                return 1, 2, 3, 4
        obj = Obj()
        r = Rect(obj)
        self.assertEqual(r, Rect(1, 2, 3, 4))

    def test_float_instance(self):
        "Create an instance with floating-point co-ordinates"
        r = Rect(1.2, 3.4, 5.6, 7.8)
        self.assertEqual(r.x, 1.2)
        self.assertEqual(r.y, 3.4)
        self.assertEqual(r.w, 5.6)
        self.assertEqual(r.h, 7.8)

    def test_float_instance_as_PygameRect(self):
        "Create a Pygame Rect from a pgzero floating-point Rect"
        r = Rect(1.2, 3.4, 5.6, 7.8)
        r2 = pygame.Rect(r)
        self.assertEqual([int(i) for i in r], list(r2))

    def test_float_center(self):
        r = Rect(0, 0, 5, 5)
        self.assertEqual(r.center, (2.5, 2.5))

    def test_float_inflated(self):
        r = Rect(0, 0, 5, 5)
        self.assertEqual(r.inflate(1.5, 1.5), (-0.75, -0.75, 6.5, 6.5))

    def test_contains_point(self):
        r = Rect(0, 0, 100, 100)
        self.assertTrue((50, 50) in r)
        self.assertFalse((150, 150) in r)

    def test_contains_rect(self):
        r = Rect(0, 0, 100, 100)
        self.assertTrue((20, 20, 50, 50) in r)
        self.assertFalse((20, 20, 100, 100) in r)

    def test_not_hashable(self):
        r1 = Rect(1, 2, 3, 4)
        r2 = Rect(r1)
        self.assertEqual(r1, r2)
        self.assertIsNot(r1, r2)
        with self.assertRaises(TypeError):
            self.assertEqual({r1}, {r2})

    def test_as_tuple(self):
        t = 1, 2, 3, 4
        r1 = Rect(t)
        self.assertEqual(tuple(r1), t)

    def test_collidepoint_tuple(self):
        r = Rect(0, 0, 1, 1)
        self.assertTrue(r.collidepoint((0.5, 0.5)))


if __name__ == '__main__':
    unittest.main()
